package com.firexxx.study.asyncservlet.scene;

import com.firexxx.study.asyncservlet.task.AsyncServletTask;
import com.firexxx.study.performancetest.scene.GridResult;
import com.firexxx.study.performancetest.scene.MultiResult;
import com.firexxx.study.performancetest.scene.SingleResult;
import com.firexxx.study.performancetest.task.rest.RestArg;
import com.firexxx.study.web.RestTemplateHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;

/**
 * 每个线程执行自己的任务
 *
 * @author fireXXX
 * @date 2020/11/19 0:27
 **/
@Component
public class TestScene {

    @Autowired
    private RestTemplateHandler restTemplateHandler;

    public MultiResult start(int thread, String syncType, String taskType, int time, int count) throws InterruptedException {
        List<AsyncServletTask> tasks = new ArrayList<>();

        for (int i = 0; i < thread; i++) {
            AsyncServletTask asyncServletTask = new AsyncServletTask();
            RestArg arg = new RestArg(restTemplateHandler, "http://127.0.0.1:8080/" + syncType + "?delay=" + time + "&taskType=" + taskType);
            asyncServletTask.init(arg);
            asyncServletTask.setPvMax(count);
            new Thread(asyncServletTask).start();

            tasks.add(asyncServletTask);
        }

        long start = System.currentTimeMillis();
        MultiResult gridResult = new MultiResult();
        SingleResult tpsResult = new SingleResult("tps");
        SingleResult timeResult = new SingleResult("time");
        gridResult.getData().add(tpsResult);
        gridResult.getData().add(timeResult);

        while (true) {
            boolean end = true;
            for (AsyncServletTask asyncServletTask : tasks) {
                if (asyncServletTask.isRunning()) {
                    end = false;

                    break;
                }
            }

            calTpsAndTime(tasks, System.currentTimeMillis() - start, tpsResult.getData(), timeResult.getData());

            if (!end) {
                Thread.sleep(1000);
            } else {
                break;
            }
        }

        calTpsAndTime(tasks, System.currentTimeMillis() - start, tpsResult.getData(), timeResult.getData());

        for (AsyncServletTask asyncServletTask : tasks) {
            asyncServletTask.stop();
        }

        return gridResult;
    }

    private void calTpsAndTime(List<AsyncServletTask> tasks, long delta, List<Long> tps, List<Long> times) {
        if (delta == 0) {
            delta = 1;
        }

        long totalTime = 0;
        long totalPv = 0;

        for (AsyncServletTask asyncServletTask : tasks) {
            totalPv += asyncServletTask.getPv();

            int size = asyncServletTask.getResults().size();
            for (int i = 0; i < size; i++) {
                totalTime += asyncServletTask.getResults().get(i).getValue();
            }
        }

        if (totalPv > 0) {
            totalTime /= totalPv;
            totalPv = totalPv * 1000 / delta;

            tps.add(totalPv);
            times.add(totalTime);
        }

        System.out.println("tps : " + totalPv);
        System.out.println("time : " + totalTime);
        System.out.println();
    }

}